home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 09 - 1993 / 09.12 Dec 93 / Apple π / CAppPiDoc.cp < prev    next >
Encoding:
Text File  |  1994-11-06  |  14.5 KB  |  616 lines  |  [TEXT/KAHL]

  1. /****
  2.  * CAppPiDoc.c
  3.  *
  4.  *    Document methods for a typical application.
  5.  *
  6.  *  Copyright © 1990 Symantec Corporation.  All rights reserved.
  7.  *
  8.  ****/
  9.  
  10. #include "Global.h"
  11. #include "Commands.h"
  12. #include "CApplication.h"
  13. #include "CBartender.h"
  14. #include "CDataFile.h"
  15. #include "CDecorator.h"
  16. #include "CDesktop.h"
  17. #include "CError.h"
  18. #include "CPanorama.h"
  19. #include "CScrollPane.h"
  20. #include "CAppPiDoc.h"
  21. #include "CAppPiPane.h"
  22. #include "TBUtilities.h"
  23. #include "CWindow.h"
  24. #include <Packages.h>
  25. #include <CIntegerText.h>
  26. #include <CDLOGDirector.h>
  27.  
  28. #define    WINDAppPi        500        /* Resource ID for WIND template */
  29.  
  30. extern    CApplication *gApplication;    /* The application */
  31. extern    CBartender    *gBartender;    /* The menu handling object */
  32. extern    CDecorator    *gDecorator;    /* Window dressing object    */
  33. extern    CDesktop    *gDesktop;        /* The enclosure for all windows */
  34. extern    CBureaucrat    *gGopher;        /* The current boss in the chain of command */
  35. extern    OSType        gSignature;        /* The application's signature */
  36. extern    CError        *gError;        /* The global error handler */
  37.  
  38. #define cmdDigits    1000L
  39. #define cmdTime        1001L
  40. #define cmdStart    1002L
  41. #define cmdFast        1003L
  42.  
  43. /***
  44.  * IAppPiDoc
  45.  *
  46.  *    This is your document's initialization method.
  47.  *    If your document has its own instance variables, initialize
  48.  *    them here.
  49.  *
  50.  *    The least you need to do is invoke the default method.
  51.  *
  52.  ***/
  53.  
  54.  
  55. void CAppPiDoc::IAppPiDoc(CApplication *aSupervisor, Boolean printable)
  56.  
  57. {
  58.     CDocument::IDocument(aSupervisor, printable);
  59.     
  60.     timeCalc = false;
  61.     running = false;
  62.     numDigits = 100;
  63.     piChore = nil;
  64.     fastCalc = false;
  65. }
  66.  
  67.  
  68. /***
  69.  * Dispose
  70.  *
  71.  *    This is your document's destruction method.
  72.  *    If you allocated memory in your initialization method
  73.  *    or opened temporary files, this is the place to release them.
  74.  *
  75.  *    Be sure to call the default method!
  76.  *
  77.  ***/
  78.  
  79. void CAppPiDoc::Dispose()
  80.  
  81. {
  82.     inherited::Dispose();
  83. }
  84.  
  85.  
  86. void CAppPiDoc::Dawdle (long *maxSleep)
  87. {
  88.     if (!running && piChore != nil)  {
  89.         gApplication->CancelIdleChore (piChore);
  90.         piChore->Dispose ();
  91.         piChore = nil;
  92.     }
  93. }
  94.  
  95.  
  96. void CAppPiDoc::PiDone (char *result)
  97. {
  98.     Rect    r;
  99.     
  100.     tickCount = piChore->GetTicks ();
  101.     running = false;
  102.     
  103.     ((CAppPiPane *) itsMainPane)->SetContent (result, tickCount, numDigits);
  104.     itsMainPane->Refresh ();
  105. }
  106.  
  107.  
  108. /***
  109.  * DoCommand
  110.  *
  111.  *    This is the heart of your document.
  112.  *    In this method, you handle all the commands your document
  113.  *    deals with.
  114.  *
  115.  *    Be sure to call the default method to handle the standard
  116.  *    document commands: cmdClose, cmdSave, cmdSaveAs, cmdRevert,
  117.  *    cmdPageSetup, cmdPrint, and cmdUndo. To change the way these
  118.  *    commands are handled, override the appropriate methods instead
  119.  *    of handling them here.
  120.  *
  121.  ***/
  122.  
  123. void CAppPiDoc::DoCommand(long theCommand)
  124. {
  125.     CIntegerText        *iText;
  126.     CDLOGDirector        *dlog;
  127.     
  128.     switch (theCommand) {
  129.  
  130.         case cmdDigits:
  131.             dlog = new CDLOGDirector;
  132.             dlog->IDLOGDirector (1000, this);        //    Setup dialog
  133.             
  134.             //    Setup default value to show.
  135.             iText = (CIntegerText *) dlog->FindViewByID (4L);
  136.             iText->SetIntValue (numDigits);
  137.             
  138.             dlog->BeginModalDialog ();                //    Run dialog
  139.             dlog->DoModalDialog (cmdOK);
  140.             
  141.             numDigits = iText->GetIntValue ();        //    Get value and trash dlog.
  142.             dlog->Close (false);
  143.             dlog->Dispose ();
  144.             break;
  145.             
  146.         case cmdTime:
  147.             if (!running)
  148.                 timeCalc = !timeCalc;
  149.             break;
  150.         
  151.         case cmdFast:
  152.             if (!running)
  153.                 fastCalc = !fastCalc;
  154.             break;
  155.             
  156.         case cmdStart:
  157.             if (running)  {
  158.                 gApplication->CancelIdleChore (piChore);
  159.                 piChore->Dispose ();
  160.                 piChore = nil;
  161.                 running = false;
  162.             }  else  {
  163.                 running = true;
  164.                 if (piChore == nil)
  165.                     piChore = new CPiChore;
  166.                 piChore->InitChore (numDigits, this, timeCalc, fastCalc);
  167.                 gApplication->AssignIdleChore (piChore);
  168.             }
  169.             break;
  170.     
  171.         default:    inherited::DoCommand(theCommand);
  172.                     break;
  173.     }
  174. }
  175.  
  176.  
  177. /***
  178.  * UpdateMenus
  179.  *
  180.  *  In this method you can enable menu commands that apply when
  181.  *  your document is active.
  182.  *
  183.  *  Be sure to call the inherited method to get the default behavior.
  184.  *  The inherited method enables these commands: cmdClose, cmdSaveAs,
  185.  *  cmdSave, cmdRevert, cmdPageSetup, cmdPrint, cmdUndo.
  186.  *
  187. ***/
  188.  
  189.  void CAppPiDoc::UpdateMenus()
  190.  
  191. {
  192.     inherited::UpdateMenus();
  193.  
  194.     gBartender->CheckMarkCmd (cmdTime, timeCalc);
  195.     gBartender->CheckMarkCmd (cmdFast, fastCalc);
  196.         
  197.     if (running)  {
  198.         gBartender->DisableCmd (cmdDigits);
  199.         gBartender->DisableCmd (cmdTime);
  200.         gBartender->SetCmdText (cmdStart, "\pStop");
  201.         gBartender->EnableCmd (cmdStart);
  202.         gBartender->DisableCmd (cmdFast);
  203.         gBartender->DisableCmd (cmdSave);
  204.     }  else  {
  205.         gBartender->EnableCmd (cmdDigits);
  206.         gBartender->EnableCmd (cmdTime);
  207.         gBartender->SetCmdText (cmdStart, "\pStart");
  208.         gBartender->EnableCmd (cmdStart);
  209.         gBartender->EnableCmd (cmdFast);
  210.         gBartender->EnableCmd (cmdSave);
  211.     }
  212. }
  213.  
  214.  
  215. /***
  216.  * NewFile
  217.  *
  218.  *    When the user chooses New from the File menu, the CreateDocument()
  219.  *    method in your Application class will send a newly created document
  220.  *    this message. This method needs to create a new window, ready to
  221.  *    work on a new document.
  222.  *
  223.  *    Since this method and the OpenFile() method share the code for creating
  224.  *    the window, you should use an auxiliary window-building method.
  225.  *
  226.  ***/
  227. void CAppPiDoc::NewFile(void)
  228.  
  229. {    
  230.     Str255  wTitle;     /* Window title string.         */
  231.     short   wCount;     /* Index number of new window.  */
  232.     Str255  wNumber;    /* Index number as a string.    */
  233.     
  234.         /**
  235.          **    BuildWindow() is the method that
  236.          **    does the work of creating a window.
  237.          ** Its parameter should be the data that
  238.          **    you want to display in the window.
  239.          **    Since this is a new window, there's nothing
  240.          **    to display.
  241.          **
  242.          **/
  243.  
  244.     BuildWindow(NULL);
  245.     
  246.         /**
  247.          ** Append an index number to the
  248.          ** default name of the window.
  249.          **/
  250.          
  251.     itsWindow->GetTitle(wTitle);
  252.     wCount = gDecorator->GetWCount();
  253.     if (wCount != 1)  {
  254.         NumToString(wCount, wNumber);
  255.         ConcatPStrings(wTitle, (StringPtr) "\p ");
  256.         ConcatPStrings(wTitle, wNumber);
  257.     }
  258.     itsWindow->SetTitle(wTitle);
  259.  
  260.         /**
  261.          **    Send the window a Select() message to make
  262.          **    it the active window.
  263.          **/
  264.     
  265.     itsWindow->Select();
  266. }
  267.  
  268.  
  269. /***
  270.  * OpenFile
  271.  *
  272.  *    When the user chooses Open… from the File menu, the OpenDocument()
  273.  *    method in your Application class will let the user choose a file
  274.  *    and then send a newly created document this message. The information
  275.  *    about the file is in the SFReply record.
  276.  *
  277.  *    In this method, you need to open the file and display its contents
  278.  *    in a window. This method uses the auxiliary window-building method.
  279.  *
  280.  ***/
  281.  
  282. void CAppPiDoc::OpenFile(SFReply *macSFReply)
  283.  
  284. {
  285.     CDataFile    *theFile;
  286.     Handle        theData = NULL;
  287.     Str63        theName;
  288.     OSErr        theError;
  289.     
  290.     TRY
  291.     {
  292.     
  293.             /**
  294.              ** Create a file and send it a SFSpecify()
  295.              **    message to set up the name, volume, and
  296.              **    directory.
  297.              **
  298.              **/
  299.     
  300.         theFile = new(CDataFile);
  301.         theFile->IDataFile();
  302.         theFile->SFSpecify(macSFReply);
  303.         
  304.             /**
  305.              **    Be sure to set the instance variable
  306.              **    so other methods can use the file if they
  307.              **    need to. This is especially important if
  308.              **    you leave the file open in this method.
  309.              **    If you close the file after reading it, you
  310.              **    should be sure to set itsFile to NULL.
  311.              **
  312.              **/
  313.     
  314.         itsFile = theFile;
  315.     
  316.             /**
  317.              **    Send the file an Open() message to
  318.              **    open it. You can use the ReadSome() or
  319.              **    ReadAll() methods to get the contents of the file.
  320.              **
  321.              **/
  322.     
  323.         theFile->Open(fsRdWrPerm);
  324.         
  325.             /**
  326.              **    Make sure that the memory request to read
  327.              **    the data from the file doesn't use up any
  328.              **    of our rainy day fund and that the GrowMemory()
  329.              **    method (in the application) knows that it's OK
  330.              **    if we couldn't get enough memory.
  331.              **
  332.              **/
  333.     
  334.     
  335.         theData = theFile->ReadAll();     /* ReadAll() creates the handle */
  336.         
  337.      
  338.         
  339.         
  340.         BuildWindow(theData);
  341.     
  342.             /**
  343.              **    In your application, you'll probably store
  344.              **    the data in some form as an instance variable
  345.              **    in your document class. For this example, there's
  346.              **    no need to save it, so we'll get rid of it.
  347.              **
  348.              **/
  349.     
  350.         DisposHandle(theData);
  351.         theData = NULL;
  352.     
  353.             /**
  354.              **    In this implementation, we leave the file
  355.              **    open. You might want to close it after
  356.              **    you've read in all the data.
  357.              **
  358.              **/
  359.     
  360.         itsFile->GetName(theName);
  361.         itsWindow->SetTitle(theName);
  362.         itsWindow->Select();            /* Don't forget to make the window active */
  363.     }
  364.     
  365.     CATCH
  366.     {
  367.         /*
  368.          * This exception handler will be executed if an exception occurs
  369.          * anywhere within the scope of the TRY block above.
  370.          * You should perform any cleanup of things that won't be needed
  371.          * since the document could not be opened. By convention,
  372.          * the creator of an object is responsible for sending it
  373.          * the Dispose message. This means that we should only dispose
  374.          * of things that would not be taken care of in Dispose.
  375.          * In this case, we just make sure that the Handle theData
  376.          * has been disposed of. The exception will propagate up to
  377.          * CApplications's exception handler, which handles displaying
  378.          * an error alert.
  379.          */
  380.          
  381.          if (theData) DisposHandle( theData);
  382.          
  383.     }
  384.     ENDTRY;
  385. }
  386.  
  387.  
  388.  
  389. /***
  390.  * BuildWindow
  391.  *
  392.  *    This is the auxiliary window-building method that the
  393.  *    NewFile() and OpenFile() methods use to create a window.
  394.  *
  395.  *    In this implementation, the argument is the data to display.
  396.  *
  397.  ***/
  398.  
  399. void CAppPiDoc::BuildWindow (Handle theData)
  400.  
  401. {
  402.     CScrollPane        *theScrollPane;
  403.     CAppPiPane    *theMainPane;
  404.  
  405.         /**
  406.          **    First create the window and initialize
  407.          **    it. The first argument is the resource ID
  408.          **    of the window. The second argument specifies
  409.          **    whether the window is a floating window.
  410.          **    The third argument is the window's enclosure; it
  411.          **    should always be gDesktop. The last argument is
  412.          **    the window's supervisor in the Chain of Command;
  413.          **    it should always be the Document object.
  414.          **
  415.          **/
  416.  
  417.     itsWindow = new(CWindow);
  418.     itsWindow->IWindow(WINDAppPi, FALSE, gDesktop, this);
  419.     
  420.         /**
  421.          **    After you create the window, you can use the
  422.          **    SetSizeRect() message to set the window’s maximum
  423.          **    and minimum size. Be sure to set the max & min
  424.          **    BEFORE you send a PlaceNewWindow() message to the
  425.          **    decorator.
  426.          **
  427.          ** The default minimum is 100 by 100 pixels. The
  428.          **    default maximum is the bounds of GrayRgn() (The
  429.          **    entire display area on all screens.)
  430.          **
  431.          ** We'll use the defaults.
  432.          **
  433.          **/
  434.     
  435.         /**
  436.          ** Our window will contain a ScrollPane,
  437.          ** which in turn will contain a Panorama.
  438.          ** Now, let's create the ScrollPane.
  439.          **/
  440.  
  441.     theScrollPane = new(CScrollPane);
  442.     
  443.         /**
  444.          **    You can initialize a scroll pane two ways:
  445.          **        1. You can specify all the values
  446.          **           right in your code, like this.
  447.          **        2. You can create a ScPn resource and
  448.          **           initialize the pane from the information
  449.          **           in the resource.
  450.          **
  451.          **/
  452.  
  453.     theScrollPane->IScrollPane(itsWindow, this, 10, 10, 0, 0,
  454.                                 sizELASTIC, sizELASTIC,
  455.                                 TRUE, TRUE, TRUE);
  456.  
  457.         /**
  458.          **    The FitToEnclFrame() method makes the
  459.          **    scroll pane be as large as its enclosure.
  460.          **    In this case, the enclosure is the window,
  461.          **    so the scroll pane will take up the entire
  462.          **    window.
  463.          **
  464.          **/
  465.  
  466.     theScrollPane->FitToEnclFrame(TRUE, TRUE);
  467.  
  468.  
  469.         /**
  470.          **    itsMainPane is the document's focus
  471.          **    of attention. Some of the standard
  472.          **    classes (particularly CPrinter) rely
  473.          **    on itsMainPane pointing to the main
  474.          **    pane of your window.
  475.          **
  476.          **    itsGopher specifies which object
  477.          ** should become the gopher when the document
  478.          ** becomes active. By default
  479.          **    the document becomes the gopher. It’s
  480.          **    likely that your main pane handles commands
  481.          **    so you’ll almost always want to set itsGopher
  482.          **    to point to the same object as itsMainPane.
  483.          **
  484.          **    Note that the main pane is the
  485.          **    panorama in the scroll pane and not
  486.          **    the scroll pane itself.
  487.          **
  488.          **/
  489.  
  490.     theMainPane = new(CAppPiPane);
  491.     theMainPane->IAppPiPane(theScrollPane, this, 0, 0, 0, 0, sizELASTIC, sizELASTIC);
  492.     itsMainPane = theMainPane;
  493.     itsGopher = theMainPane;
  494.     
  495.         /**    The FitToEnclosure() method makes the pane
  496.          **    fit inside the enclosure. The inside (or
  497.          **    interior) of a scroll pane is defined as
  498.          **    the area inside the scroll bars.
  499.          **/
  500.  
  501.     theMainPane->FitToEnclosure(TRUE, TRUE);
  502.  
  503.         /**
  504.          **    Send the scroll pane an InstallPanorama()
  505.          ** message to associate the panorama with 
  506.          ** the scroll pane.
  507.          **
  508.          **/
  509.  
  510.     theScrollPane->InstallPanorama(theMainPane);
  511.     
  512.         /**
  513.          **    The Decorator is a global object that takes care
  514.          **    of placing and sizing windows on the screen.
  515.          **    You don't have to use it.
  516.          **
  517.          **/
  518.  
  519.     gDecorator->PlaceNewWindow(itsWindow);
  520. }
  521.  
  522.  
  523. /***
  524.  * DoSave
  525.  *
  526.  *    This method handles what happens when the user chooses Save from the
  527.  *    File menu. This method should return TRUE if the file save was successful.
  528.  *    If there is no file associated with the document, you should send a
  529.  *    DoSaveFileAs() message.
  530.  *
  531.  ***/
  532.  
  533. Boolean CAppPiDoc::DoSave(void)
  534.  
  535. {
  536.     char    *s;
  537.     
  538.         /**
  539.          **    If you closed your file in your NewFile() method,
  540.          **    you'll need a different way than this to determine
  541.          **    if there's a file associated with your document.
  542.          **
  543.          **/
  544.  
  545.     if (itsFile == NULL)
  546.         return(DoSaveFileAs());
  547.     else {
  548.             
  549.         s = ((CAppPiPane *) itsMainPane)->GetContent ();
  550.         if (s != nil)
  551.             ((CDataFile *) itsFile)->WriteSome (s, numDigits);
  552.                 
  553.         dirty = FALSE;                    /* Document is no longer dirty        */
  554.         gBartender->DisableCmd(cmdSave);
  555.         return(TRUE);                    /* Save was successful                */
  556.     }
  557. }
  558.  
  559.  
  560. /***
  561.  * DoSaveAs
  562.  *
  563.  *    This method handles what happens when the user chooses Save As… from
  564.  *    File menu. The default DoCommand() method for documents sends a DoSaveFileAs()
  565.  *    message which displays a standard put file dialog and sends this message.
  566.  *    The SFReply record contains all the information about the file you're about
  567.  *    to create.
  568.  *
  569.  ***/
  570.  
  571. Boolean CAppPiDoc::DoSaveAs(SFReply *macSFReply)
  572.  
  573. {
  574.         /**
  575.          **    If there's a file associated with this document
  576.          **    already, close it. The Dispose() method for files
  577.          **    sends a Close() message to the file before releasing
  578.          **    its memory.
  579.          **
  580.          **/
  581.          
  582.     if (itsFile != NULL)
  583.         itsFile->Dispose();
  584.  
  585.  
  586.         /**
  587.          **    Create a new file, and then save it normally.
  588.          **
  589.          **/
  590.  
  591.     itsFile = new(CDataFile);
  592.     ((CDataFile *)itsFile)->IDataFile();
  593.     itsFile->SFSpecify(macSFReply);
  594.     itsFile->CreateNew(gSignature, 'TEXT');
  595.     itsFile->Open(fsRdWrPerm);
  596.     
  597.     itsWindow->SetTitle(macSFReply->fName);
  598.  
  599.     return( DoSave() );
  600. }
  601.  
  602.  
  603. /***
  604.  * DoRevert
  605.  *
  606.  *    If your application supports the Revert command, this method
  607.  *    should close the current file (without writing anything out)
  608.  *    and read the last saved version of the file.
  609.  *
  610.  ***/
  611.  
  612. void CAppPiDoc::DoRevert(void)
  613.  
  614. {
  615. }
  616.